package com.shenglaotuan.community.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shenglaotuan.community.common.entity.JwtConfig;
import com.shenglaotuan.community.common.exception.InsertException;
import com.shenglaotuan.community.common.service.EncodeService;
import com.shenglaotuan.community.common.service.MailService;
import com.shenglaotuan.community.common.utils.FileUtils;
import com.shenglaotuan.community.user.entity.User;
import com.shenglaotuan.community.user.exception.*;
import com.shenglaotuan.community.user.mapper.UserMapper;
import com.shenglaotuan.community.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ruidong
 * @since 2020-08-03
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MailService mailService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private EncodeService encodeService;

    @Autowired
    private JwtConfig jwtConfig;

    @Value("${user.code.email.subject}")
    private String subject;
    @Value("${user.code.email.content}")
    private String content;
    @Value("${user.code.email.duration}")
    private long emailDuration;
    @Value("${user.invate-code}")
    private String iCode;
    @Value("${config.jwt.expire}")
    private long tokenDuration;
    @Value("${default-path.avatar}")
    private String defaultAvatar;
    @Value("${user-info.field}")
    private List<String> userEnableGetField;
    @Value("${static.filePath}")
    private String staticPath;
    @Value("${dir-path.temp}")
    private String tempPath;


    @Override
    public void sendCode(String email) {
        // 调用持久层方法，查看邮箱地址是否存在
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email", email);
        User user = userMapper.selectOne(wrapper);
        // 判断user是否不为空
        if(user != null){
            // 是：EmailDuplicateException
            throw new EmailDuplicateException("该邮箱已被使用！");
        }
        // 查询redis中的验证码
        String code = (String) redisTemplate.opsForValue().get("code-" + email);
        // 判断验证码是否存在
        if(!StringUtils.isEmpty(code)){
            // 是：CodeExistException
            throw new CodeExistException("操作频繁，请稍后再试！");
        }
        // 生成验证码
        code = UUID.randomUUID().toString().substring(0, 6);
        // 替换文字
        String finalContent = content.replaceAll("\\{code\\}", code);
        // 将code放入redis
        redisTemplate.opsForValue().set("code-" + email, code, emailDuration, TimeUnit.MINUTES);
        // 发送邮件
        mailService.sendSimpleMailMessge(email, subject, finalContent);
    }

    @Override
    public String reg(String username, String password, String email, String validCode, String invateCode) {
        // 根据用户名查询查询用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User result = userMapper.selectOne(wrapper);
        // 判断用户是否不为空
        if(result != null){
            // 是：UsernameDuplicateException
            throw new UsernameDuplicateException("该用户名已被使用！");
        }
        // 查询redis中的验证码
        String code = (String) redisTemplate.opsForValue().get("code-" + email);
        // 判断验证码是否不正确
        if(!validCode.equals(code)){
            // 是：ValidCodeNotMatchException
            throw new ValidCodeNotMatchException("验证码错误！");
        }
        // 判断邀请码是否不正确
        if(!iCode.equals(invateCode)){
            // 是：ValidCodeNotMatchException
            throw new InvateCodeNotMatchException("邀请码错误！");
        }
        // 生成盐值
        String salt = UUID.randomUUID().toString();
        // 加密密码
        String md5Password = encodeService.getMD5Password(password, salt);
        // 创建user对象
        User user = new User();
        // 赋值
        user.setUsername(username);
        user.setEmail(email);
        user.setPassword(md5Password);
        user.setSalt(salt);
        user.setNickname(username);
        user.setAvatar(defaultAvatar);
        // 调用方法插入数据
        int rows = userMapper.insert(user);
        if(rows != 1){
            throw new InsertException("注册失败，请稍后再试");
        }
        // 生成token
        String token = jwtConfig.createToken(user.getId().toString());
        // 将token值放入redis
        redisTemplate.opsForValue().set("token-" + user.getId(), token, tokenDuration, TimeUnit.SECONDS);
        return token;
    }

    @Override
    public String login(String username, String password) {
        // 根据用户名查询查询用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User result = userMapper.selectOne(wrapper);
        // 判断用户是否为空
        if(result == null){
            // 是：UserNotExistException
            throw new UserNotExistException("该用户不存在！");
        }
        // 加密用户输入的密码
        String md5Password = encodeService.getMD5Password(password, result.getSalt());
        // 判断加密后的密码是否不正确
        if(!md5Password.equals(result.getPassword())){
            // 是：PasswordNotMatchException
            throw new PasswordNotMatchException("密码错误!");
        }
        // 生成token
        String token = jwtConfig.createToken(result.getId().toString());
        // 将token值放入redis
        redisTemplate.opsForValue().set("token-" + result.getId(), token, tokenDuration, TimeUnit.SECONDS);
        return token;
    }

    @Override
    public void logout(String token) {
        // 获取token中的id
        Long id = Long.parseLong(jwtConfig.getTokenClaim(token).getSubject());
        // 去除redis存的token信息
        redisTemplate.delete("token-" + id);
    }

    @Override
    public User getInfo(String uid, String[] fields) {
        // 数组转列表
        List<String> fieldsList = Arrays.stream(fields).collect(Collectors.toList());
        // 遍历将不存在的字段剔除
        for (int i = fieldsList.size() - 1; i >= 0 ; i--) {
            if(!userEnableGetField.contains(fieldsList.get(i))){
                fieldsList.remove(i);
            }
        }
        // 根据条件获取用户信息
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // 若符合要求的字段数量为0，就不执行查询
        if(fieldsList.size() != 0){
            wrapper
                    .eq("id", uid)
                    .select(fieldsList.toArray(new String[0]));
            User user = userMapper.selectOne(wrapper);
            return user;
        }else{
            return new User();
        }

    }

    @Override
    public String changeNickname(String nickname, String id) {
        // 查询昵称是否被占用
        if(userMapper.selectOne(new QueryWrapper<User>().eq("nickname", nickname)) != null){
            throw new NicknameDuplicateException("昵称已被使用！");
        }
        User entity = new User();
        entity.setNickname(nickname);
        entity.setId(id);
        // 查询版本
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("version").eq("id", id);
        User user = userMapper.selectOne(wrapper);
        // 设置当前版本
        entity.setVersion(user.getVersion());
        // 更新数据
        userMapper.updateById(entity);
        return entity.getNickname();
    }

    @Override
    public void changePassword(String password, String id) {
        // 查询用户
        User user = userMapper.selectById(id);
        // 加密密码
        String md5Password = encodeService.getMD5Password(password, user.getSalt());
        // 设置密码
        user.setPassword(md5Password);
        // 更新数据
        userMapper.updateById(user);
    }

    @Override
    public String changeAvatar(String avatar, String id) {
        // 查询原来的头像路径
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("avatar","id").eq("id", id);
        User user = userMapper.selectOne(wrapper);
        // 判断头像是否为默认头像
        if(!defaultAvatar.equals(user.getAvatar())){
            // 不是：则移动原头像位置
            FileUtils.MVFile(staticPath + user.getAvatar(), staticPath + tempPath + user.getAvatar());
        }
        // 修改数据库中的头像
        user.setAvatar(avatar);
        userMapper.updateById(user);
        return avatar;
    }
}
